package com.example.gobang.game;

import com.example.gobang.model.UserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

/**
 * Description: 这个类负责完成匹配功能
 * Date: 2024-09-05
 * Time: 16:39
 */
@Slf4j
@Component
public class Matcher {
    // 分为初级、中级、高级三个段位
    private Queue<UserInfo> primaryQueue = new LinkedList<>();
    private Queue<UserInfo> normalQueue = new LinkedList<>();
    private Queue<UserInfo> advancedQueue = new LinkedList<>();

    @Autowired
    private OnlineUserManager onlineUserManager;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    /**
     * 把玩家放到匹配队列中
     * @param user
     */
    public void add(UserInfo user) {
        if (user.getScore() < 1800) {
            synchronized (primaryQueue) {
                primaryQueue.add(user);
                // 有新玩家进来的时候就唤醒之前等待的进程
                primaryQueue.notify();
                log.info("把玩家 " + user.getUserName() + " 加到 primaryQueue 中了");
            }
        } else if (user.getScore() >= 1800 && user.getScore() < 2500) {
            synchronized (normalQueue) {
                normalQueue.add(user);
                normalQueue.notify();
                log.info("把玩家 " + user.getUserName() + " 加到 normalQueue 中了");
            }
        } else {
            synchronized (advancedQueue) {
                advancedQueue.add(user);
                advancedQueue.notify();
                log.info("把玩家 " + user.getUserName() + " 加到 advancedQueue 中了");
            }
        }
    }

    /**
     * 当玩家点击停止匹配时，将玩家从对应的匹配队列中移除
     * @param user
     */
    public void remove(UserInfo user) {
        if (user.getScore() < 1800) {
            synchronized (primaryQueue) {
                primaryQueue.remove(user);
                log.info("把玩家 " + user.getUserName() + " 从队列 primaryQueue 中移除");
            }
        } else if (user.getScore() >= 1800 && user.getScore() < 2500) {
            synchronized (normalQueue) {
                normalQueue.remove(user);
                log.info("把玩家 " + user.getUserName() + " 从队列 normalQueue 中移除");
            }
        } else {
            synchronized (advancedQueue) {
                advancedQueue.remove(user);
                log.info("把玩家 " + user.getUserName() + " 从队列 advancedQueue 中移除");
            }
        }
    }

    public void handlerMatch(Queue<UserInfo> matchQueue) throws IOException, InterruptedException {
        synchronized (matchQueue) {
            // 1.检查队列元素是否 >= 2，如果没有，那就阻塞等待
            while (matchQueue.size() < 2)
                matchQueue.wait();
            UserInfo player1 = matchQueue.poll();
            UserInfo player2 = matchQueue.poll();
            log.info("匹配到玩家：" + player1.getUserName() + " 和 " + player2.getUserName());

            // 2.获取到玩家的 WebSocket 会话，目的是为了告诉玩家匹配到对手了
            WebSocketSession session1 = onlineUserManager.getFromGameHall(player1.getUserId());
            WebSocketSession session2 = onlineUserManager.getFromGameHall(player2.getUserId());
            // 3.把两位玩家放到游戏房间中
            Room room = new Room();
            roomManager.add(room,player1.getUserId(),player2.getUserId());
            // 4.给玩家反馈信息：匹配到对手了
            // 通过 websocket 返回一个 message 为 "matchSuccess" 的响应
            // 这里需要给两位玩家都返回 "匹配成功" 的信息，所以需要返回两次
            MatchResponse response1 = new MatchResponse();
            response1.setOk(true);
            response1.setMessage("matchSuccess");
            String json1 = objectMapper.writeValueAsString(response1);
            session1.sendMessage(new TextMessage(json1));

            MatchResponse response2 = new MatchResponse();
            response2.setOk(true);
            response2.setMessage("matchSuccess");
            String json2 = objectMapper.writeValueAsString(response2);
            session2.sendMessage(new TextMessage(json2));
        }
    }

    /**
     * 创建三个线程，分别对这三个匹配队列进行操作
     * 每个线程就是负责扫描匹配队列
     */
    public Matcher() {
        Thread t1 = new Thread() {
            @SneakyThrows
            @Override
            public void run() {
                while (true) {
                    handlerMatch(primaryQueue);
                }
            }
        };
        t1.start();

        Thread t2 = new Thread() {
            @SneakyThrows
            @Override
            public void run() {
                while (true) {
                    handlerMatch(normalQueue);
                }
            }
        };
        t2.start();

        Thread t3 = new Thread() {
            @SneakyThrows
            @Override
            public void run() {
                while (true) {
                    handlerMatch(advancedQueue);
                }
            }
        };
        t3.start();

    }
}
